package com.sn.author.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.sn.author.domain.BaseResult;
import com.sn.author.common.enums.ExceptionEnum;
import com.sn.author.common.exception.AException;
import com.sn.author.common.exception.BadRequestException;
import com.sn.author.utils.AESUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * All controller router's exception handler
 * @author chen
 */
@RestControllerAdvice({"com.sn.author.controller"})
@Slf4j
public class ControllerExceptionHandler {

    /**
     * Global exception interceptor. Write to response. Just for OWCException .
     * @param e Exception example
     * @return error data
     */
    @ExceptionHandler({AException.class})
    public ResponseEntity<String> handleHaloException(AException e) throws Exception {
        BaseResult<Object> baseResponse = handleBaseException(e);
        baseResponse.setCode(e.getCode());
        baseResponse.setData("");
        return new ResponseEntity<>(AESUtil.encrypt(JSON.toJSONString(baseResponse, SerializerFeature.DisableCircularReferenceDetect)), HttpStatus.OK);
    }



    @ExceptionHandler({BadRequestException.class})
    public ResponseEntity<String> handlerBadException(BadRequestException ex) throws Exception {
        BaseResult<Object> baseResponse = handleBaseException(ex);
        baseResponse.setCode(ex.getCode());
        baseResponse.setData("");
        return new ResponseEntity<>(AESUtil.encrypt(JSON.toJSONString(baseResponse, SerializerFeature.DisableCircularReferenceDetect)), HttpStatus.OK);
    }

    /**
     * Interceptor exception.
     */
    @ExceptionHandler({Exception.class})
    public ResponseEntity<String> handlerException(Exception e) throws Exception {
        BaseResult<Object> baseResponse = handleBaseException(e);
        baseResponse.setCode(ExceptionEnum.UNKNOWN_ERR.getCode());
        baseResponse.setData("");
        return new ResponseEntity<>(AESUtil.encrypt(JSON.toJSONString(baseResponse, SerializerFeature.DisableCircularReferenceDetect)), HttpStatus.OK);
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseEntity<String> methodArgumentNotValidHandler(MethodArgumentNotValidException e) throws Exception {
        BaseResult<Object> baseResponse = new BaseResult<>();
        String errMessage = e.getBindingResult().getFieldErrors().get(0).getDefaultMessage();
        baseResponse.setMessage(errMessage);
        baseResponse.setCode(ExceptionEnum.PARAMS_MISS_ERR.getCode());
        baseResponse.setData("");
        log.error(e.getMessage());
        return new ResponseEntity<>(AESUtil.encrypt(JSON.toJSONString(baseResponse, SerializerFeature.DisableCircularReferenceDetect)), HttpStatus.OK);
    }

    private <T> BaseResult<T> handleBaseException(Throwable t) {
        Assert.notNull(t, "Throwable must not be null");

        log.error("Captured an exception throw message", t);

        BaseResult<T> baseResponse = new BaseResult<>();
        baseResponse.setMessage(t.getMessage());

        //If is debug level, record throw stack message.
        if (log.isDebugEnabled()) {
            baseResponse.setDevMessage(ExceptionUtils.getStackTrace(t));
        }
        return baseResponse;
    }
}
